#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <D3DX9.h>
#include <ddraw.h>
#include <fstream>

#include "globals.h"
#include "ddBitmap.h"
#include "ddUtilities.h"
#include "player.h"
#include "defines.h"

#pragma comment(lib,"dxerr9.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"ddraw.lib")
#pragma comment(lib,"dsound.lib")
#pragma comment(lib,"dinput8.lib")
#pragma comment(lib,"dsetup.lib")
#pragma comment(lib,"dxguid.lib")

BOOL gFullScreen = true;
BOOL gFinished = false;
BOOL activeApp = true;
HINSTANCE gHInstance;
HWND mainWinHandle;

ddUtilities				ddUtil;
ddBitmap				bmp; 
ddBitmap				playerBmp;
player					player1;
int zDelta;
int frame = 0;
int show_frame = 0;

LRESULT CALLBACK p_defaultWinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{   
	PAINTSTRUCT ps; // Used by WM_PAINT
	HDC			hdc; // device context handle

	switch(Msg)
	{
		case WM_ACTIVATE:
			if (LOWORD(wParam) == WA_INACTIVE)
			{
				ShowCursor(true);
				activeApp = false;
			}
			else
			{
				ShowCursor(false);
				activeApp = true;
			}
			return 0;
		case WM_CREATE:
			// Initialize
			return 0;
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);

			// Painting / rendering here

			EndPaint(hWnd, &ps);
			return 0;
		case WM_KEYDOWN:     // A key has been pressed, end the app if it's ESC
			if (wParam == VK_ESCAPE) 
			{
				PostQuitMessage(0);
				gFinished = true;
				return 0;
			}
			break;
		case WM_MOUSEWHEEL:
			zDelta = ((short)HIWORD(wParam))/120;
			player1.xVel += zDelta;
			player1.yVel += zDelta;
			if (player1.xVel < 0)
				player1.xVel = 0;
			if (player1.xVel > 150)
				player1.xVel = 150;

			if (player1.yVel < 0)
				player1.yVel = 0;
			if (player1.yVel > 150)
				player1.yVel = 150;
			return 0;
			break;
		case WM_DESTROY:
		case WM_CLOSE:       //User hit the Close Window button, end the app	
			PostQuitMessage(0);
			gFinished = true;
			return 0;
	}

	return DefWindowProc(hWnd, Msg, wParam, lParam);
}

int initializeGame(void *params = NULL, int numParms = 0)
{	
	player1.x = 0;
	player1.y = 0;
	player1.xVel = 3;
	player1.yVel = 3;

	if (FAILED(DirectDrawCreateEx(NULL, (LPVOID *)&lpdd7, IID_IDirectDraw7, NULL)))
	{
		return(0);
	}

	if (FAILED(lpdd7->SetCooperativeLevel(mainWinHandle, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWMODEX | DDSCL_ALLOWREBOOT)))
	{
		return(0);
	}

	if (FAILED(lpdd7->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0)))
	{
		return(0);
	}

	if (FAILED(ddUtil.buildSurface()))
	{
		return(0);
	}
	
	ddUtil.ddFillSurface(lpddsprimary, 0);
	ddUtil.ddFillSurface(lpddsback, 0);
	lpddsbackground = bmp.loadBitmapFile(L"tilephoto13.bmp", ddUtil);
	lpddssprite = playerBmp.loadBitmapFile(L"sprite.bmp", ddUtil, true);

	return(1);
}

int renderScreen(void *params = NULL, int numParms = 0)
{
	if (gFinished)
		return 0;

	ddUtil.ddFillSurface(lpddsback, 0);
	bmp.ddDrawFullBackground(player1, lpddsbackground, lpddsback);
	playerBmp.ddDrawSprite(lpddssprite, lpddsback, 20, SCREEN_HEIGHT - 100, 100, 100, 0, show_frame);

	// We have to test if we lost our surfaces and restore them if so
	if (lpddsprimary->Flip(NULL, DDFLIP_WAIT) == DDERR_SURFACELOST)
	{
		lpddsbackground->Restore();
		lpddsback->Restore();
		lpddsprimary->Restore();
	}

	return(1);
}

int processGame(void *params = NULL, int numParms = 0)
{
	if (KEYDOWN(VK_ESCAPE))
	{
		SendMessage(mainWinHandle, WM_CLOSE, 0, 0);
	}
	if (KEYDOWN(VK_LEFT))
	{
		player1.x -= player1.xVel;
		if (player1.x <= -1 * MIN(bmp.bmWidth, SCREEN_WIDTH))
			player1.x += bmp.bmWidth;

		frame += 1;
		
		if (frame > MIN(3, 10 - player1.xVel))
		{
			frame = 0;
			show_frame -= 1;
			if (show_frame < 0)
			{
				show_frame = 3;
			}
		}
	}
	if (KEYDOWN(VK_RIGHT))
	{
		player1.x += player1.xVel;
		if (player1.x >= MIN(bmp.bmWidth, SCREEN_WIDTH))
			player1.x -= bmp.bmWidth;

		frame += 1;
		
		if (frame > MIN(3, 10 - player1.xVel))
		{
			frame = 0;
			show_frame += 1;
			if (show_frame > 3)
			{
				show_frame = 0;
			}
		}
	}
	if (KEYDOWN(VK_UP))
	{
		player1.y -= player1.yVel;
		if (player1.y <= -1 * MIN(bmp.bmHeight, SCREEN_HEIGHT))
			player1.y += bmp.bmHeight;
	}
	if (KEYDOWN(VK_DOWN))
	{
		player1.y += player1.yVel;
		if (player1.y >= MIN(bmp.bmHeight, SCREEN_HEIGHT))
			player1.y -= bmp.bmHeight;
	}

	renderScreen();
	return(1);
}

int shutdownGame(void *params = NULL, int numParms = 0)
{
	ShowCursor(true);
	if (lpddpal)
	{
		lpddpal ->Release();
		lpddpal = NULL;
	}
	if (lpddsbackground)
	{
		lpddsbackground->Release();
		lpddsbackground = NULL;
	}
	if (lpddsback)
	{
		lpddsback->Release();
		lpddsback = NULL;
	}
	if (lpddsprimary)
	{
		lpddsprimary->Release();
		lpddsprimary = NULL;
	}
	if (lpdd7)
	{
		lpdd7->Release();
		lpdd7 = NULL;
	}
	return(1);
}

HWND buildWindow(HINSTANCE hInstance, LPCWSTR winTitle, int xPos, int yPos, int width, int height, DWORD style)
{
	WNDCLASSEX newWindow;
	HWND hWnd;

	newWindow.cbSize = sizeof(WNDCLASSEX);
	newWindow.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
	newWindow.lpfnWndProc = p_defaultWinProc;
	newWindow.cbClsExtra = 0;
	newWindow.cbWndExtra = 0;
	newWindow.hInstance = hInstance;
	newWindow.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	newWindow.hCursor = LoadCursor(NULL, IDC_ARROW);
	newWindow.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	newWindow.lpszMenuName = NULL;
	newWindow.lpszClassName = WINDOW_CLASS;
	newWindow.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassEx(&newWindow))
	{
		// Problem Registering Class
		return NULL;
	}
	else
	{
		if (!(hWnd = CreateWindow(WINDOW_CLASS,
								  winTitle,
								  style,
								  xPos, yPos,
								  width, height,
								  NULL,
								  NULL,
								  hInstance,
								  NULL)))
		{
			// Problem creating Window
			return NULL;
		}
		else
		{
			return hWnd;
		}
	}
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	DWORD displayStyle;
	int displayWidth, displayHeight;
	if (gFullScreen)
	{
		displayWidth = SCREEN_WIDTH;
		displayHeight = SCREEN_HEIGHT;
		displayStyle = WS_POPUP | WS_VISIBLE;
	}
	else
	{
		displayWidth = SCREEN_WIDTH;
		displayHeight = SCREEN_HEIGHT;
		displayStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
	}

	mainWinHandle = buildWindow(hInstance, L"Direct X Window", 0, 0, displayWidth, displayHeight, displayStyle);

	if (mainWinHandle != NULL)
	{
		gHInstance = hInstance;

		MSG msg;
		HDC hdc = GetDC(mainWinHandle);

		if (initializeGame())
		{
			while (!gFinished)
			{
				DWORD startTime = GetTickCount();

			   while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			   {
				  TranslateMessage(&msg);
				  DispatchMessage(&msg);
			   }

				if (activeApp)
				{
					// Lock FPS to 30 FPS (1/30 -> 33.33)
					while ((GetTickCount() - startTime) < 17);
					processGame();
				}
			}

			shutdownGame();

			return((int)msg.wParam);
		}
		else
		{
			return 0;
		}
	}
	else
	{
		return 0;
	}
}